package com.jdk.learn.nio._04;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by ricky
 * on 2018/2/9.
 * <p>
 * 非阻塞网络NIO
 * <p>
 * 使用NIO完成网络通信的三个核心：
 * 1. 通道(Channel)：负责连接
 * java.nio.{@link java.nio.channels.Channel}
 * java.nio.{@link java.nio.channels.SelectableChannel}
 * java.nio.{@link java.nio.channels.SocketChannel}
 * java.nio.{@link java.nio.channels.ServerSocketChannel}
 * java.nio.{@link java.nio.channels.DatagramChannel}
 * <p>
 * java.nio.{@link java.nio.channels.Pipe.SinkChannel}
 * java.nio.{@link java.nio.channels.Pipe.SourceChannel}
 * <p>
 * 2.缓冲区(Buffer):负责数据的存取
 * <p>
 * 3.选择器(Selector):是SelectableChannel的多路复用器。用于监听SelectableChannel的IO状况。
 */
public class NIONetDemo {


    /**
     * 客户端
     */
    @Test
    public void ClientBlock() {
        SocketChannel client = null;
        FileChannel channel = null;

        try {
            //连接到服务端
            client = SocketChannel.open(
                    new InetSocketAddress("127.0.0.1", 9999)
            );
            //传输文件通道
            channel = FileChannel.open(
                    Paths.get("ricky.png"),
                    StandardOpenOption.READ
            );

            //缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            while (channel.read(buf) != -1) {
                buf.flip();
                client.write(buf);
                buf.clear();
            }
            client.shutdownOutput();//告诉服务端传送结束
            int len = 0;
            while ((len = client.read(buf)) != -1) {
                buf.flip();
                System.out.println(new String(buf.array(), 0, len));
                buf.clear();
            }
//            client.shutdownInput();//告诉服务端接收结束
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                channel.close();
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 服务端
     */
    @Test
    public void ServerBlock() {
        ServerSocketChannel server = null;
        FileChannel channel = null;

        try {
            //连接到服务端
            server = ServerSocketChannel.open();
            server.bind(new InetSocketAddress(9999));
            //传输文件通道
            channel = FileChannel.open(
                    Paths.get("rickynew.png"),
                    StandardOpenOption.WRITE,
                    StandardOpenOption.READ,
                    StandardOpenOption.CREATE
            );
            SocketChannel accept = server.accept();
            //缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            System.out.println("等待进入..");
            while (accept.read(buf) != -1) {
                buf.flip();
                channel.write(buf);
                buf.clear();
            }
            System.out.println("复制完毕..");
            buf.put("接收完毕".getBytes());
            buf.flip();
            accept.write(buf);
            accept.shutdownOutput();//告知传输完毕
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                channel.close();
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


    /**
     * 客户端
     */
    @Test
    public void ClientNonBlock() {
        SocketChannel client = null;
        try {
            //连接到服务端
            client = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9999));

            client.configureBlocking(false);//设置为非阻塞

            //缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
            buf.put("ricky".getBytes());
            buf.flip();
            client.write(buf);
            buf.clear();
            client.shutdownInput();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (client!=null) {
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 非阻塞服务端
     */
    @Test
    public void ServerNonBlock() {
        ServerSocketChannel server = null;
        FileChannel channel = null;

        try {
            //连接到服务端
            server = ServerSocketChannel.open();
            server.configureBlocking(false);//开启非阻塞
            server.bind(new InetSocketAddress(9999));

            Selector selector = Selector.open();

            server.register(selector, SelectionKey.OP_ACCEPT);//将通道注册到监听事件中，注册接收事件

            while (selector.select() > 0) {
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey sk = iterator.next();
                    try {
                        if (sk.isAcceptable()) {
                            System.out.println("接收到了连接");
                            SocketChannel accept = server.accept();
                            accept.configureBlocking(false);
                            accept.register(selector, SelectionKey.OP_READ);
                        }else if (sk.isReadable()) {
                          //  System.out.println("开始读取");
                            SocketChannel read = (SocketChannel) sk.channel();
                            ByteBuffer buf=ByteBuffer.allocate(1024);

                            int len=0;
                            while ((len=read.read(buf))>0) {
                                buf.flip();
                                System.out.println("server: client-------"+new String( buf.array(),0,len)+"---------");
                                buf.clear();
                            }
                            read.register(selector, SelectionKey.OP_WRITE);
                        }else if(sk.isWritable()){
                            System.out.println("写");
                            ServerSocketChannel write= (ServerSocketChannel) sk.channel();
                            ByteBuffer allocate = ByteBuffer.allocate(1024);
                            allocate.put("hello,ricky".getBytes());
                            write.close();
                        }
                        iterator.remove();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }

            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                channel.close();
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


}
